import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV

# https://www.kaggle.com/code/navoshta/grid-knn/data

def knncls():
    """
    K近邻算法预测入住位置类别
    :return:
    """
    # 一、处理数据以及特征工程
    # 1、读取收
    data = pd.read_csv("../resources/p01_machine_learning_sklearn/FBlocation/train.csv")

    # 2、数据处理
    # 1）数据逻辑筛选操作，缩小数据的范围 df.query()
    data = data.query("x > 1.0 & x < 1.25 & y > 2.5 & y < 2.75")
    # 2）处理时间特征
    time_value = pd.to_datetime(data["time"], unit="s")
    date = pd.DatetimeIndex(time_value)
    data["day"] = date.day
    data["weekday"] = date.weekday
    data["hour"] = date.hour
    # 3）删除入住次数少于三次位置
    place_count = data.groupby('place_id').count()["row_id"]
    tf = place_count[place_count > 3].index.values
    data_final = data[data['place_id'].isin(tf)]

    # 3、取出特征值和目标值
    y = data_final['place_id']
    # y = data[['place_id']]
    x = data_final[["x","y","accuracy","day","weekday","hour"]]

    # 4、数据分割与特征工程
    # （1）、数据分割
    x_train, x_test, y_train, y_test = train_test_split(x, y)
    # (2)、标准化
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.transform(x_test)  # 测试集使用训练集的数据（平均值）等进行标准化
    # (3).KNN 算法预估器
    estimator = KNeighborsClassifier()
    # 4.1 加入网格搜索与交叉验证
    param_dict = {"n_neighbors": [3, 5, 7, 9]}
    estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
    estimator.fit(x_train, y_train)
    # (4).模型评估
    # 方法一：直接比对预测值与真实值
    y_predict = estimator.predict(x_test)
    print("y_predict:\n", y_predict)
    print("y_test:\n", y_test)
    print("预测值与真实值比对：\n", y_predict == y_test)
    # 方法二：计算准确率
    score = estimator.score(x_test, y_test)
    print("准确率为：\n", score)

    # 最佳参数 best_params_
    print("最佳参数：\n", estimator.best_params_)
    # 最佳结果 best_score_
    print("最佳结果：\n", estimator.best_score_)
    # 最佳估计器 best_estimator_
    print("最佳估计器：\n", estimator.best_estimator_)
    # 交叉验证结果 cv_results_
    print("交叉验证结果：\n", estimator.cv_results_)

    return None

if __name__ == "__main__":
    knncls()